<script>
import fecha from "element-ui/src/utils/date";
import {
  range as rangeArr,
  getFirstDayOfMonth,
  getPrevMonthLastDays,
  getMonthDays,
  getI18nSettings,
  validateRangeInOneMonth,
} from "element-ui/src/utils/date-util";

export default {
  props: {
    selectedDay: String, // formated date yyyy-MM-dd
    range: {
      type: Array,
      validator(val) {
        if (!(val && val.length)) return true;
        const [start, end] = val;
        return validateRangeInOneMonth(start, end);
      },
    },
    date: Date,
    hideHeader: Boolean,
    firstDayOfWeek: Number,
    dutyData: Array,
  },

  inject: ["elCalendar"],

  methods: {
    toNestedArr(days) {
      return rangeArr(days.length / 7).map((_, index) => {
        const start = index * 7;
        return days.slice(start, start + 7);
      });
    },

    getFormateDate(day, type) {
      if (!day || ["prev", "current", "next"].indexOf(type) === -1) {
        throw new Error("invalid day or type");
      }
      let prefix = this.curMonthDatePrefix;
      if (type === "prev") {
        prefix = this.prevMonthDatePrefix;
      } else if (type === "next") {
        prefix = this.nextMonthDatePrefix;
      }
      day = `00${day}`.slice(-2);
      return `${prefix}-${day}`;
    },

    getCellClass({ text, type }) {
      const classes = [type];
      if (type === "current") {
        const date = this.getFormateDate(text, type);
        if (date === this.selectedDay) {
          classes.push("is-selected");
        }
        if (date === this.formatedToday) {
          classes.push("is-today");
        }
      }
      return classes;
    },

    pickDay({ text, type }) {
      const date = this.getFormateDate(text, type);
      this.$emit("pick", date);
    },

    cellRenderProxy({ text, type }) {
      let render = this.elCalendar.$scopedSlots.dateCell;
      if (!render) return <span>{text}</span>;

      const day = this.getFormateDate(text, type);
      const date = new Date(day);
      const data = {
        isSelected: this.selectedDay === day,
        type: `${type}-month`,
        day,
      };
      return render({ date, data });
    },
    showDuty(cell) {
      let data = this.dutyData[cell.text - 1];
      if (cell.type == "current" && data != undefined) {
        return <div class="duty-info">{data}</div>;
      }
    },
  },

  computed: {
    WEEK_DAYS() {
      console.log(getI18nSettings().dayNames);
      return getI18nSettings().dayNames;
    },
    prevMonthDatePrefix() {
      const temp = new Date(this.date.getTime());
      temp.setDate(0);
      return fecha.format(temp, "yyyy-MM");
    },

    curMonthDatePrefix() {
      return fecha.format(this.date, "yyyy-MM");
    },

    nextMonthDatePrefix() {
      const temp = new Date(
        this.date.getFullYear(),
        this.date.getMonth() + 1,
        1
      );
      return fecha.format(temp, "yyyy-MM");
    },

    formatedToday() {
      return this.elCalendar.formatedToday;
    },

    isInRange() {
      return this.range && this.range.length;
    },

    rows() {
      let days = [];
      // if range exists, should render days in range.
      if (this.isInRange) {
        const [start, end] = this.range;
        const currentMonthRange = rangeArr(
          end.getDate() - start.getDate() + 1
        ).map((_, index) => ({
          text: start.getDate() + index,
          type: "current",
        }));
        let remaining = currentMonthRange.length % 7;
        remaining = remaining === 0 ? 0 : 7 - remaining;
        const nextMonthRange = rangeArr(remaining).map((_, index) => ({
          text: index + 1,
          type: "next",
        }));
        days = currentMonthRange.concat(nextMonthRange);
      } else {
        const date = this.date;
        let firstDay = getFirstDayOfMonth(date);
        firstDay = firstDay === 0 ? 7 : firstDay;
        const firstDayOfWeek =
          typeof this.firstDayOfWeek === "number" ? this.firstDayOfWeek : 0;
        const offset = (7 + firstDay - firstDayOfWeek) % 7;
        const prevMonthDays = getPrevMonthLastDays(date, offset).map((day) => ({
          text: day,
          type: "prev",
        }));
        const currentMonthDays = getMonthDays(date).map((day) => ({
          text: day,
          type: "current",
        }));
        days = [...prevMonthDays, ...currentMonthDays];
        const nextMonthDays = rangeArr(7 - prevMonthDays.length).map(
          (_, index) => ({
            text: index + 1,
            type: "next",
          })
        );
        days = days.concat(nextMonthDays);
      }
      return this.toNestedArr(days);
    },

    weekDays() {
      const start = this.firstDayOfWeek;
      const { WEEK_DAYS } = this;

      if (typeof start !== "number" || start === 0) {
        return WEEK_DAYS.slice();
      } else {
        return WEEK_DAYS.slice(start).concat(WEEK_DAYS.slice(0, start));
      }
    },
  },

  render() {
    const thead = this.hideHeader ? null : (
      <thead>
        {this.weekDays.map((day) => (
          <th key={day}>星期{day}</th>
        ))}
      </thead>
    );
    return (
      <table
        class={{
          "el-calendar-table": true,
          "is-range": this.isInRange,
        }}
        cellspacing="0"
        cellpadding="0"
      >
        {thead}
        <tbody>
          {this.rows.map((row, index) => (
            <tr
              class={{
                "el-calendar-table__row": true,
                "el-calendar-table__row--hide-border":
                  index === 0 && this.hideHeader,
              }}
              key={index}
            >
              {row.map((cell, key) => (
                <td
                  key={key}
                  class={this.getCellClass(cell)}
                  onClick={this.pickDay.bind(this, cell)}
                >
                  <div class="el-calendar-day">
                    <div class="day-number"> {this.cellRenderProxy(cell)}</div>
                    {this.showDuty(cell)}
                  </div>
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    );
  },
};
</script>

<style scoped>
.el-calendar-day {
  display: flex;
  flex-flow: column;
  height: 105px !important;
}

.day-number {
  flex: 1;
}

p {
  padding: 0;
  margin: 0;
}

.duty-info {
  font-size: 12px;
  color: #666;
}

.current .day-number {
  color: white;
}

.current .duty-info {
  color: white;
}

.el-calendar-table .el-calendar-day:hover {
  background-color: unset;
}
</style>
